#include "log_server.h"
#include "log/log.h"
#include "srt/srt.h"
#include "common/common.h"
#include "uart_interface.h"
#include "pico/mutex.h"
#include <stdio.h>
#include <stdarg.h>
#include <string.h>


static mutex_t lock_;  // 锁
static Bool    is_init_ = False;  // 是否已初始化
static UInt8   print_buf_[4096+128];

static const Int8 log_level_color_arr_[] = {
    36,  ///< S 青色
    34,  ///< A 蓝色
    31,  ///< E 红色
    33,  ///< W 黄色
    32,  ///< I 绿色
    32,  ///< D 绿色
    37,  ///< T 白色
};


static const Int8* log_level_str_arr_[] = {
    "S",
    "A",
    "E",
    "W",
    "I",
    "D",
    "T",
};

static const Int8 char_hex_arr_[] = {
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};

static const Int8 GetLogLevelColor(UInt8 level)
{
    return log_level_color_arr_[level];
}

static const Int8 *GetLogLevelStr(UInt8 level)
{
    return log_level_str_arr_[level];
}

static const Int8 get_ch_by_hex(UInt8 hex)
{
    return char_hex_arr_[hex];
}

void TLog(UInt8 level, const Int8 *tag,
          const Int8 *file_name, const Int8 *func_name, Int32 line,
          const Int8 *format, ...)
{
    Bool is_log_enable = False;

    TSrtGetBool(kSrtBoolLogEnable, &is_log_enable);

    if (is_init_ && is_log_enable)
    {
        va_list args;
        Int32 tag_len = 0;
        Int32 content_len = 0;

        mutex_enter_blocking(&lock_);

        tag_len = snprintf(print_buf_, sizeof(print_buf_),
                        "\033[%dm%09u [%s <%s> %s:%s:%d] ", GetLogLevelColor(level), TGetTicks(),
                        GetLogLevelStr(level), tag, file_name, func_name, line);
        va_start(args, format);
        content_len = vsnprintf(&print_buf_[tag_len], sizeof(print_buf_) - tag_len, format, args);
        va_end(args);
        if (content_len > sizeof(print_buf_) - tag_len - 7)
            content_len = sizeof(print_buf_) - tag_len - 7;

        memcpy(&print_buf_[tag_len + content_len], "\033[37m\r\n", 7);

        TUartSendData(print_buf_, tag_len + content_len + 7);

        mutex_exit(&lock_);
    }
}

static Int32 Bin2Str(UInt8 *out_buf, Int32 out_buf_size, const Int8 *in_bin, Int32 in_bin_size)
{
    Int32 ret_len = 0;

    for (Int32 idx = 0; idx < in_bin_size && ret_len < out_buf_size - 1; idx++)
    {
        UInt8 byte = in_bin[idx];

        out_buf[ret_len++] = get_ch_by_hex(byte >> 4);
        out_buf[ret_len++] = get_ch_by_hex(byte & 0x0f);
    }

    return ret_len;
}

void TLogHex(UInt8 level, const Int8 *tag,
             const Int8 *file_name, const Int8 *func_name, Int32 line,
             const UInt8 *buf_tag,
             const UInt8 *buf, Int16 buf_size)
{
    Bool is_log_enable = False;

    TSrtGetBool(kSrtBoolLogEnable, &is_log_enable);

    if (is_init_ && is_log_enable)
    {
        Int32 tag_len = 0;
        Int32 content_len = 0;

        mutex_enter_blocking(&lock_);
        tag_len = snprintf(print_buf_, sizeof(print_buf_),
                        "\033[%dm%09u [%s <%s> %s:%s:%d] %s[%d]: ", GetLogLevelColor(level), TGetTicks(),
                        GetLogLevelStr(level), tag, file_name, func_name, line, buf_tag, buf_size);

        content_len = Bin2Str(&print_buf_[tag_len], sizeof(print_buf_) - tag_len, buf, buf_size);

        if (content_len > sizeof(print_buf_) - tag_len - 7)
            content_len = sizeof(print_buf_) - tag_len - 7;

        memcpy(&print_buf_[tag_len + content_len], "\033[37m\r\n", 7);

        TUartSendData(print_buf_, tag_len + content_len + 7);

        mutex_exit(&lock_);
    }
}

void TLogStr(UInt8 level, const Int8 *tag,
             const Int8 *file_name, const Int8 *func_name, Int32 line,
             const UInt8 *buf_tag,
             const UInt8 *buf, Int16 buf_size)
{
    Bool is_log_enable = False;

    TSrtGetBool(kSrtBoolLogEnable, &is_log_enable);

    if (is_init_ && is_log_enable)
    {
        Int32 tag_len = 0;
        Int32 content_len = 0;

        mutex_enter_blocking(&lock_);
        tag_len = snprintf(print_buf_, sizeof(print_buf_),
                        "\033[%dm%09u [%s <%s> %s:%s:%d] %s[%d]: ", GetLogLevelColor(level), TGetTicks(),
                        GetLogLevelStr(level), tag, file_name, func_name, buf_tag, buf_size);

        if (sizeof(print_buf_) - tag_len < buf_size - 7)
            content_len = sizeof(print_buf_) - tag_len - 7;
        else
            content_len = buf_size;

        memcpy(&print_buf_[tag_len], buf, content_len);

        memcpy(&print_buf_[tag_len + content_len], "\033[37m\r\n", 7);

        TUartSendData(print_buf_, tag_len + content_len + 7);

        mutex_exit(&lock_);
    }
}

Bool TLogServerInit(void)
{
    mutex_init(&lock_);

    TSrtSetBool(kSrtBoolLogEnable, False);

    is_init_ = True;

    return is_init_;
}

Bool TLogServerFini(void)
{
    is_init_ = False;

    return is_init_;
}
